﻿/*
	[ru]	Пример работы с 3Д звуком.
			Управление:
				[ ]						- общая громкость звука
				< >						- громкость источника звука
				+ -						- тон звука
				W A S D SHIFT SPACE		- изменить направление звука
				arrows, NUMPAD UP/DOWN	- изменить позицию источника звука
				ENTER					- установить значения по умолчанию
*/

#include "Engine.h"
using namespace Engine;



class CExample : public ICoreEventListener
{
private:
	CFontMaterial		cFont;

	CSoundBufferPtr		pSoundBuffer;
	CSoundPtr			pSound;
	float				fLastTime;

	float				fListenerVolume,
						fSoundVolume,
						fSoundPitch;
	vec3				vSoundPos,
						vSoundDir;

	const float			fVolumeStep;
	const float			fDirStep;
	const float			fPosStep;
	const float			fPitchStep;

public:
	CExample(): fLastTime(0), fVolumeStep(0.01f), fDirStep(0.01f), fPosStep(0.1f), fPitchStep(0.01f)
	{
	}

	~CExample()
	{
	}
	
	void Draw();
	void Process();

	virtual void OnInit();
	virtual void OnFree();

	virtual void OnUpdate();

	virtual void Release()									{ delete this; }
	virtual e_win_event::type GetEvents()					{ return e_win_event::UNKNOWN; }

	virtual void ProcessMessage(const TWindowEvent &sEvent)	{}
	virtual void OnException()								{}
	
	static int s_RunEngine();
};


static const string		s_sControls(
	"[ ]                                                   - listener volume\n"
	"< >                                                   - sound source volume\n"
	"+ -	                                                   - pitch\n"
	"ENTER                                            - default settings\n"
	"WASD, SHIFT, CTRL               - change direction\n"
	"arrows, NUMPAD UP/DOWN  - change position" );



inline void CExample::Draw()
{
	RENDERGL()->ClearBuffers();
	
	RENDERGL()->Mode2D();
	cFont.DrawMultiline( rectf(-1.f, -1.f, 1.f, 1.f), s_sControls, color4u() );
	
	BATCH()->Flush();
	BATCH()->Clear();

	RENDERGL()->SwapBuffers();
}


inline void CExample::Process()
{
	INPUT()->Update();

	if ( INPUT()->IsKey( e_key::ESCAPE ) )
		CORE()->QuitEngine();


	// Change listener volume //
	if ( INPUT()->IsKey( e_key::RBRACKET ) )
	{
		fListenerVolume += fVolumeStep;
		SOUNDSYS()->SetListenerVolume( fListenerVolume );
	}
	else
	if ( INPUT()->IsKey( e_key::LBRACKET ) )
	{
		fListenerVolume -= fVolumeStep;
		SOUNDSYS()->SetListenerVolume( fListenerVolume );
	}


	// Sound sample volume //
	if ( INPUT()->IsKey( e_key::COMMA ) )
	{
		fSoundVolume -= fVolumeStep;
		pSound->SetVolume( fSoundVolume );
	}
	else
	if ( INPUT()->IsKey( e_key::PERIOD ) )
	{
		fSoundVolume += fVolumeStep;
		pSound->SetVolume( fSoundVolume );
	}


	// Sound sample pitch //
	if ( INPUT()->IsKey( e_key::PLUS ) )
	{
		fSoundPitch += fPitchStep;
		pSound->SetPitch( fSoundPitch );
	}
	else
	if ( INPUT()->IsKey( e_key::MINUS ) )
	{
		fSoundPitch -= fPitchStep;
		pSound->SetPitch( fSoundPitch );
	}


	// Change sound direction //
	if ( INPUT()->IsKey( e_key::W ) )			vSoundDir.x += fDirStep;
	if ( INPUT()->IsKey( e_key::S ) )			vSoundDir.x -= fDirStep;
	if ( INPUT()->IsKey( e_key::A ) )			vSoundDir.y += fDirStep;
	if ( INPUT()->IsKey( e_key::D ) )			vSoundDir.y -= fDirStep;
	if ( INPUT()->IsKey( e_key::SPACE ) )		vSoundDir.z += fDirStep;
	if ( INPUT()->IsKey( e_key::LSHIFT ) )		vSoundDir.z -= fDirStep;

	vSoundDir.Normalize();
	pSound->SetDirection( vSoundDir );


	// Change sound position //
	if ( INPUT()->IsKey( e_key::UP ) )			vSoundPos.y += fPosStep;
	if ( INPUT()->IsKey( e_key::DOWN ) )			vSoundPos.y -= fPosStep;
	if ( INPUT()->IsKey( e_key::LEFT ) )			vSoundPos.x += fPosStep;
	if ( INPUT()->IsKey( e_key::RIGHT ) )		vSoundPos.x -= fPosStep;
	if ( INPUT()->IsKey( e_key::NUMPADUP ) )		vSoundPos.z += fPosStep;
	if ( INPUT()->IsKey( e_key::NUMPADDOWN ))	vSoundPos.z -= fPosStep;

	pSound->SetPosition( vSoundPos );


	// Reset sound params //
	if ( INPUT()->IsKeyClick( e_key::RETURN ) )
	{
		vSoundPos		= vec3(0.f);
		vSoundDir		= vec3(0.f);
		fSoundVolume	= 1.f;
		fSoundPitch		= 1.f;
		fListenerVolume	= 1.f;

		pSound->SetPosition( vSoundPos );
		pSound->SetDirection( vSoundDir );
		pSound->SetVolume( fSoundVolume );
		pSound->SetPitch( fSoundPitch );
		SOUNDSYS()->SetListenerVolume( fListenerVolume );
	}

	INPUT()->Reset();
}


void CExample::OnInit()
{
	bool	ret = true;

	ret = RESMAN()->Load( e_resource::SOUND_BUFFER, pSoundBuffer, "Mr Sizef - Patriot.snd" );

	if ( ret )
	{
		pSoundBuffer->CreateSound( pSound );
		pSound->SetLooped( true );
		pSound->SetDirection( vec3(0.f, 0.f, 1.f) );
		
		vSoundPos		= pSound->GetPosition();
		vSoundDir		= pSound->GetDirection();
		fSoundVolume	= pSound->GetVolume();
		fSoundPitch		= pSound->GetPitch();
		
		pSound->Play();

		SOUNDSYS()->SetListenerPosition( vec3(0.f) );
		SOUNDSYS()->SetListenerVolume( 1.f );
		fListenerVolume = 1.f;
	}
	
	ret = cFont.Load( "LucidaConsole.fnt", e_def_program::FONT_GS );
	cFont.SetPrimitiveType( gl_primitive::POINT );
	cFont.SetScale( 0.045f );

	RENDERGL()->SetClearColor( color4f(0.f) );
	RENDERGL()->SetClearDepth( 1.f );

	SMAN()->BlendFunc( gl_blend_func::SRC_ALPHA, gl_blend_func::ONE_MINUS_SRC_ALPHA );
	SMAN()->Enable( e_gl_state::BLEND );
	SMAN()->Disable( e_gl_state::DEPTH_TEST );

	ASSERT( ret );
}


void CExample::OnFree()
{
}


void CExample::OnUpdate()
{
	CORE()->Update();
	Draw();
	
	fLastTime += CORE()->GetUpdateTimeDelta();

	if ( fLastTime > 1.f/60.f )
	{
		fLastTime = 0.f;
		Process();
	}
}


int CExample::s_RunEngine()
{
	CExample	*		p_example			= new CExample();
	TEngInitParams		s_init_params;
	e_log_output::bits	e_log_bits			= e_log_output::LOG_FILE_BIT
											DEBUG_ONLY( | e_log_output::MESSAGE_BIT )
											;
	
	s_init_params.eFlags					= e_eng_init_flags::OPENGL_4_2
											| e_eng_init_flags::CORE_PROFILE
											| e_eng_init_flags::EXTENDED_CONTEXT
											//| e_eng_init_flags::DEBUG_MODE
											//| e_eng_init_flags::STREAMED_LOAD
											//| e_eng_init_flags::STEREO
											//| e_eng_init_flags::ES2_PROFILE
											;
	s_init_params.sApplicationName			= "3D Sound Sample";
	s_init_params.sClassName				= "";
	s_init_params.pHandle					= nullptr;
	s_init_params.pIcon						= nullptr;

	s_init_params.sAudioParams.sAudioDevice	= "";

	s_init_params.sRenInit.uColorDepth		= 32;
	s_init_params.sRenInit.uZBufferDepth	= 24;
	s_init_params.sRenInit.uStencilDepth	= 0;
	s_init_params.sRenInit.uColorSamples	= 0;
	s_init_params.sRenInit.uCSAASamples		= 0;
	s_init_params.sRenInit.uMSAASamples		= 0;
	s_init_params.sRenInit.uPixelFormat		= 0;

	s_init_params.sRenParams.bFullScreen	= false;
	s_init_params.sRenParams.bVSync			= true;
	s_init_params.sRenParams.eMode			= e_window_mode::ALLOW_SIZING | e_window_mode::CENTERED;
	s_init_params.sRenParams.sWinPos		= ivec2( 0, 0 );
	s_init_params.sRenParams.sWinSize		= ivec2( 640, 480 );
	
	s_init_params.sExtParams.uLogLevel		= 15;
	s_init_params.sExtParams.eLogFilter		= e_log_msg::FILTER_ALL;
	s_init_params.sExtParams.eResManFlags	= e_resman_flags::FREE_NON_REF | e_resman_flags::SET_DEFAUL_RES;
	s_init_params.sExtParams.sResDirectory	= "data";
	s_init_params.uLoadThreads				= 0;
	s_init_params.uRenderThreads			= 0;
	
	if ( !RunEngine( p_example, s_init_params, e_log_bits, "log.html", "data\\config\\settings.ocf" ) )
		return 1;

	return 0;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	return CExample::s_RunEngine();
}